package com.zorn.platform.user.service.impl;

import static com.alibaba.fastjson.util.TypeUtils.castToInt;
import static com.alibaba.fastjson.util.TypeUtils.castToString;
import static com.alibaba.fastjson.util.TypeUtils.castToTimestamp;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.jasypt.util.password.BasicPasswordEncryptor;
import org.jasypt.util.password.PasswordEncryptor;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zorn.core.provider.ServiceSupportProvider;
import com.zorn.core.util.ParameterParser;
import com.zorn.platform.global.Setting;
import com.zorn.platform.user.dao.UserDao;
import com.zorn.platform.user.service.IUserProfileService;
import com.zorn.platform.user.service.IUserRoleService;
import com.zorn.platform.user.service.IUserService;

@Service
public class UserService extends ServiceSupportProvider implements IUserService {

	/* Fields
	================================================== */
	private UserDao userDao;
	private PasswordEncryptor passwordEncryptor = new BasicPasswordEncryptor();

	//	private IComponentQuerier componentQuerier;

	/* Extension methods
	================================================== */
	@Override
	public Map<String, Object> login(Map<String, Object> params) {
		final String account = castToString(params.get("account"));
		final String password = castToString(params.get("password"));
		final String captcha = castToString(params.get("captcha"));

		if (checkInput(account, password, captcha)) {
			Map<String, Object> user = userDao.getUserByAccount(account);
			if (checkUser(user)) {
				setResult(getUserContext(user));
				setSessionAttributes("uid", castToInt(user.get("id")));
			}
		}

		return getResult();
	}

	/**
	 * 检查用户输入是否正确有效
	 * @param account 用户名
	 * @param password 明文密码
	 * @param captcha 验证码
	 * @return 是否正确
	 */
	private boolean checkInput(String account, String password, String captcha) {
		if (StringUtils.isEmpty(account) || StringUtils.isEmpty(password)) {
			setResult(false, "用户名和密码不可为空。");
			return false;
		}
		return checkCaptcha(captcha) && checkPassword(account, password);
	}

	/**
	 * 检查输入的验证码是否正确 不区分大小写
	 * @param captcha 验证码
	 * @return 是否正确
	 */
	private boolean checkCaptcha(String captcha) {
		String origin = castToString(getSession(true).getAttribute("captcha"));
		if (StringUtils.equalsIgnoreCase(origin, captcha)) {
			return true;
		} else {
			setResult(false, "验证码不正确。");
			return false;
		}
	}

	/**
	 * 检查用户密码是否正确
	 * @param account 用户名
	 * @param password 明文密码
	 * @return 是否正确
	 */
	private boolean checkPassword(String account, String password) {
		final String pwd = userDao.getEncryptedPassword(account);
		if (pwd == null || pwd.length() != 32) {
			setResult(false, Setting.getString("Platform.login.UserNotExist", "用户不存在。"));
			if (needCaptcha()) getResult().put("captcha", true);
			return false;
		}
		if (passwordEncryptor.checkPassword(password, pwd)) {
			return true;
		} else {
			setResult(false, Setting.getString("Platform.login.BadPassword", "密码不正确。"));
			if (needCaptcha()) getResult().put("captcha", true);
			return false;
		}
	}

	private boolean needCaptcha() {
		/*HttpSession session = getSession(true);
		Policy.getString();
		String countStrategy = PlatformStrategies.getString("Platform.login.BadInputCountStrategy");
		if (countStrategy.equalsIgnoreCase("Global")) {
			session.setAttribute("Platform.login.BadInputCounter", NumberUtils.toInt(ObjectUtils.toString(session.getAttribute("Platform.login.BadInputCounter"), null)) + 1);
		}
		if (countStrategy.equalsIgnoreCase("Single")) {

		}
		int counter = PlatformStrategies.getInt("Platform.login.AccountBadInputCaptchaCounter");
		return getSession(true).getAttribute("AccountBadInputCaptchaCounter") >= counter;*/
		return false;
	}

	private boolean checkUser(Map<String, Object> user) {
		int status = castToInt(user.get("status"));
		Timestamp expire = castToTimestamp(user.get("expire"));

		return checkUserStatus(status) && checkUserExpire(expire);
	}

	/**
	 * 检查用户状态并设置返回结果
	 * @param status 状态
	 * @return 是否可用
	 */
	private boolean checkUserStatus(int status) {
		switch (status) {
		case 0:
			setResult(false, "用户已被禁用。");
			break;
		case 1:
			return true;
		default:
			setResult(false, "用户状态不明，已被限制登录。");
			break;
		}
		return false;
	}

	/**
	 * 检查用户过期时间并设置返回结果
	 * @param expire 过期时间
	 * @return 是否可用
	 */
	private boolean checkUserExpire(Timestamp expire) {
		if (expire == null) return true;

		if (expire.compareTo(new Timestamp(System.currentTimeMillis())) > 0) {
			return true;
		} else {
			setResult(false, "用户已过期。");
			return false;
		}
	}

	private Map<String, Object> getUserContext(Map<String, Object> user) {
		Map<String, Object> context = new HashMap<String, Object>(5), params = new HashMap<String, Object>(2);
		final int uid = castToInt(user.get("id"));

		params.put("user_id", uid);
		params.put("available", true);

		IUserProfileService userProfileService = (IUserProfileService) getBean(IUserProfileService.class);
		IUserRoleService userRoleService = (IUserRoleService) getBean(IUserRoleService.class);

		final JSONObject profile = JSON.parseObject(userProfileService.getProfile(uid));
		final List<Map<String, Object>> roles = userRoleService.getRoles(params);
		final List<Map<String, Object>> components = userDao.getComponents(params);

		context.put("success", true);
		context.put("user", user);
		context.put("roles", roles);
		context.put("profile", profile);
		context.put("components", components);

		return context;
	}

	private void setSessionAttributes(Object... attributes) {
		HttpSession session = getSession(true);
		for (int i = 0; i < attributes.length; i++) {
			session.setAttribute(castToString(attributes[i++]), attributes[i++]);
		}
	}

	@Override
	public int logout(Map<String, Object> params) {
		return 0;
	}

	/* Basic
	================================================== */
	@Override
	public List<Map<String, Object>> query(Map<String, Object> params) {
		params = ParameterParser.parse(params);
		List<Map<String, Object>> data = userDao.query(params);

		return setQueryResult(isPaging() ? userDao.count(params) : data.size(), data);
	}

	@Override
	public int count(Map<String, Object> params) {
		return setCountResult(userDao.count(params));
	}

	@Override
	public String insert(Map<String, Object> params) {
		return setInsertResult(userDao.insert(params), MapUtils.getString(params, "id"));
	}

	@Override
	public int update(Map<String, Object> params) {
		return setUpdateResult(userDao.update(params));
	}

	@Override
	public int delete(Map<String, Object> params) {
		return setDeleteResult(userDao.delete(params));
	}

	@Override
	public List<Map<String, Object>> getComponents(Map<String, Object> params) {
		return userDao.getComponents(params);
	}

	/* Getters & Setters
	================================================== */
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

}